function ShowMusic(audio, id) {
    this.create(audio, id);
}

ShowMusic.prototype.create = function (audio, id) {
    // 预先检查
    if (!this.check(audio)) return;

    audio.crossOrigin = "anonymous";

    this.id = id || 'show_music_box';

    this.audio = audio;
    this.analyser = null;
    this.canvas = null;
    this.actx = null;
    this.ctx = null;
    this.stopFlag = false;
    this.sleepTimes = 0;
    this.sleepMax = 5;
    this.zIndex = 999999;
    this.hideLeft = '-999999px';
    this.initLeft = '0px';
    this.num = 120;
    this.colors = [];
    this.initColors();
    this.init();
    this.createAnalyser();
}

ShowMusic.prototype.initColors = function () {
    this.colors = [];
    for (let i = 0; i < this.num; i++) this.colors.push(this.getRandomColor());
}

ShowMusic.prototype.init = function () {
    let me = this;

    let activeHandler = function (e) {
        me.sleepTimes = 0;
        me.autoShow();
    }

    document.removeEventListener('mousedown', activeHandler);
    document.addEventListener('mousedown', activeHandler);

    setInterval(function () {
        me.sleepTimes++;
        if (me.sleepTimes > 999) {
            me.sleepTimes = 999;
        }
        me.autoShow();
    }, 1000);

    let resizeHandler = function () {
        me.resize();
    }

    window.removeEventListener('resize', resizeHandler);
    window.addEventListener('resize', resizeHandler);
}

ShowMusic.prototype.autoShow = function () {
    if (this.canvas == null || this.actx == null || this.audio == null) return;
    if (this.canvas.style.left == this.hideLeft && this.isSleeped() && !this.audio.paused) {
        this.canvas.style.left = this.initLeft;
    }
    if (this.canvas.style.left == this.initLeft && !this.isSleeped()) {
        this.canvas.style.left = this.hideLeft;
    }
}

ShowMusic.prototype.isSleeped = function () {
    return this.sleepTimes > this.sleepMax;
}

ShowMusic.prototype.resize = function () {
    if (this.canvas != null) {
        this.canvas.width = window.innerWidth;
        this.canvas.height = window.innerHeight;
    }
}

ShowMusic.prototype.check = function (audio) {
    window.AudioContext = window.AudioContext || window.webkitAudioContext ||
        window.mozAudioContext;
    if (window.AudioContext == null) {
        console.log('AudioContex 不支持');
        return false;
    }
    if (typeof requestAnimationFrame != 'function') {
        console.log('requestAnimationFrame 不支持');
        return false;
    }
    if (audio == null) {
        console.log('audio 参数为空');
        return false;
    }
    return true;
}

ShowMusic.prototype.createAnalyser = function () {
    this.actx = new AudioContext();
    let audioSrc = this.actx.createMediaElementSource(this.audio);
    this.analyser = this.actx.createAnalyser();
    audioSrc.connect(this.analyser);
    this.analyser.connect(this.actx.destination);
    let oldCanvas = document.getElementById(this.id);
    if (oldCanvas) {
        document.body.removeChild(oldCanvas);
    }
    this.canvas = document.createElement("canvas");
    this.canvas.id = this.id;
    this.resize();
    this.canvas.style.backgroundColor = "rgba(0,0,0,0.1)";
    this.canvas.style.left = this.hideLeft;
    this.canvas.style.top = "0px";
    this.canvas.style.position = "fixed";
    this.canvas.style.zIndex = this.zIndex;
    this.ctx = this.canvas.getContext("2d");
    document.body.appendChild(this.canvas);
    this.draw();
}

ShowMusic.prototype.getRandomColor = function () {
    return '#' + Math.floor(Math.random() * 0xffffff).toString(16);
}

ShowMusic.prototype.draw = function () {
    if (this.canvas == null || this.audio == null) return;
    let num = this.num;
    let cWidth = this.canvas.width;
    let cHeight = this.canvas.height;
    let cWidthHalf = cWidth * .5;
    let gap = Math.round(cWidth / num);
    let voiceHigh = new Uint8Array(this.analyser.frequencyBinCount);
    this.analyser.getByteFrequencyData(voiceHigh);
    let step = Math.round(voiceHigh.length / num);
    this.ctx.clearRect(0, 0, cWidth, cHeight);
    let vals = [];
    for (var i = 0; i < num; i++) {
        vals.push(voiceHigh[step * i] || 0);
    }
    if (new Date().getTime() % 300 == 0) this.initColors();
    var showStyle = 1;
    // 画小圆球
    if (showStyle == 0) {
        // 画左边
        moveTo(cWidthHalf, cHeight);
        for (let i = num - 1; i > 0; i--) {
            let value = voiceHigh[step * i] || 0;
            let x = i * -gap + cWidthHalf;
            let y = -value + cHeight;
            this.ctx.beginPath();
            this.ctx.fillStyle = this.colors[i];
            this.ctx.arc(x, y, value * 0.1, 0, Math.PI * 2, true);
            this.ctx.fill();
            this.ctx.closePath();
        }
        // 画右边
        moveTo(cWidthHalf, cHeight);
        for (let i = 0; i < num; i++) {
            let value = voiceHigh[step * i] || 0;
            let x = i * gap + this.canvas.width * 0.5;
            let y = -value + this.canvas.height * 1;
            this.ctx.beginPath();
            this.ctx.fillStyle = this.colors[i];
            this.ctx.arc(x, y, value * 0.1, 0, Math.PI * 2, true);
            this.ctx.fill();
            this.ctx.closePath();
        }
    }

    // 画振动线
    if (showStyle == 1) {
        this.ctx.beginPath();
        // 画左边
        moveTo(0, cHeight);
        for (let i = num - 1; i > 0; i--) {
            let value = voiceHigh[step * i] || 0;
            let x = i * -gap + cWidthHalf;
            let y = -value + cHeight;
            this.ctx.lineTo(x, y);
        }
        // 画右边
        moveTo(cWidthHalf, cHeight);
        for (let i = 0; i < num; i++) {
            let value = voiceHigh[step * i] || 0;
            let x = i * gap + this.canvas.width * 0.5;
            let y = -value + this.canvas.height * 1;
            this.ctx.lineTo(x, y);
        }

        this.ctx.closePath();
        this.ctx.strokeStyle = this.colors[0];
        this.ctx.stroke();
    }

    // 画柱子
    if (showStyle == 2) {
        var maxVal = Math.max.apply(this, vals);
        var lineColor = this.ctx.createLinearGradient(
            cWidthHalf, cHeight, cWidthHalf, cHeight - maxVal);
        lineColor.addColorStop(0, 'yellow');
        lineColor.addColorStop(0.5, 'red');
        lineColor.addColorStop(1, 'brown');
        // 画左边
        moveTo(cWidthHalf, cHeight);
        for (let i = num - 1; i > 0; i--) {
            let value = voiceHigh[step * i] || 0;
            let x = i * -gap + cWidthHalf;
            let y = -value + cHeight;
            this.ctx.beginPath();
            this.ctx.fillStyle = lineColor;
            this.ctx.rect(x, y, 1, value);
            this.ctx.fill();
            this.ctx.closePath();
        }
        // 画右边
        moveTo(cWidthHalf, cHeight);
        for (let i = 0; i < num; i++) {
            let value = voiceHigh[step * i] || 0;
            let x = i * gap + this.canvas.width * 0.5;
            let y = -value + this.canvas.height * 1;
            this.ctx.beginPath();
            this.ctx.fillStyle = lineColor;
            this.ctx.rect(x, y, 1, value);
            this.ctx.fill();
            this.ctx.closePath();
        }
    }

    let me = this;
    if (!this.stopFlag) requestAnimationFrame(function () {
        me.draw();
    });
}